﻿//// Underwater Collector v2
//// Original by Superyeti
//// Updated by 23051602
////
//// Simplified and updated code to be able to use with Herb/Miner or Herb or Mine only
//// Should support any underwater node that is a mine or herb (also lower level than max)
////


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
//using System.Windows.Forms;
using System.Windows.Media;
using System.Xml.Linq;
//using System.Drawing;

using Styx;
using Styx.Common;
using Styx.Helpers;
using Styx.Plugins;
using Styx.WoWInternals;
using Styx.WoWInternals.Misc;
using Styx.WoWInternals.World;
using Styx.WoWInternals.WoWObjects;
using Styx.Pathing;
using Styx.CommonBot.Frames;
using Styx.CommonBot;



/* Credits to Hazard for all the code from RepCollector */

namespace CollectUnderWater
{
    class CollectUnderWater : HBPlugin
    {
        public static string name { get { return "UnderWater Collector v2.1e "; } }
        public override string Name { get { return name; } }
        public override string Author { get { return "23051602 and Superyeti"; } }
        private readonly static Version _version = new Version(2, 1);
        public override Version Version { get { return _version; } }
        public override string ButtonText { get { return "Don't touch me"; } }
        public override bool WantButton { get { return false; } }
        public static LocalPlayer Me { get { return StyxWoW.Me; } }
        private static WoWGameObject myHerbNodeObject = null;
        private static WoWGameObject myMineNodeObject = null;
        private static WoWGameObject myLootedObject = null;
        private static WoWGameObject myTargetObject = null;
        private static List<WoWGameObject> myObjList = null;

        private static List<WoWGameObject> myBlacklistedObjects = new List<WoWGameObject>();



		
		
        public override void Pulse()
        {
            bool foundObject = false;
            try
            {
                //Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: in Pulse"));
                GetObjectList();
                if (!Me.Combat && !Me.IsDead)
                    objs();



                if ((Me.IsSwimming || Me.Z < 0) && !Me.Combat && !Me.IsDead && myTargetObject == null)
                {
                    Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: I am swimming in Pulse"));
                    foreach (WoWGameObject wgo in myObjList)
                    {
                        Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Trying to find node"));
                        if (wgo == myLootedObject)
                        {
                            foundObject = true;
                        }
                    }
                    if (foundObject == false)
                    {
                        Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: I am swimming trying to asscend"));
                        WoWMovement.Move(WoWMovement.MovementDirection.JumpAscend, TimeSpan.FromMilliseconds(2000));
                    }

                }
            }
            catch (ThreadAbortException)
            {
            }
        }

        public override void Initialize()
        {
            base.Initialize();
            Logging.Write(Styx.Common.LogLevel.Normal, Colors.LightSeaGreen, 
                string.Format("Starting " + Name + " Version " + Version.ToString()));
        }

        
        public static bool isNode(WoWGameObject aObject)
        {

            //Check if it's a Herb or Mineral and if you have the profession to get it. No check for skill level.
            if (aObject.IsHerb && TrainingSkills.HasLearnt(SkillLine.Herbalism))
            {                
                return true;
            }
            else if (aObject.IsMineral && TrainingSkills.HasLearnt(SkillLine.Mining))
            {   
                return true;
            }
            return false;
        }
				
		public static void LogGathered(WoWGameObject aObject)
		{
            Logging.Write(Styx.Common.LogLevel.Normal, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Gathered " + aObject.Name + "."));
		}

        public static void LogApproaching(WoWGameObject aObject)
		{
            Logging.Write(Styx.Common.LogLevel.Normal, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Approaching " + aObject.Name + " at " + 
                "X=" + aObject.Location.X.ToString("G") + ", Y=" + aObject.Location.Y.ToString("G") + ", Z=" + aObject.Location.Z.ToString("G")));
		}

        public static bool CheckGameObjectForBlacklist(WoWGameObject aObject)
        {
            /*
            if (Blacklist.Contains(aObject, BlacklistFlags.Node))
                return false;
            return true;
              */      
            
            foreach (WoWGameObject obj in myBlacklistedObjects)
            {
                if (aObject == obj)
                    return true;
            }
            return false;
        }

        static public void GetObjectList()
        {
            ObjectManager.Update();
            myObjList = ObjectManager.GetObjectsOfType<WoWGameObject>()
                .Where(objs => (objs.Distance <= 100 && (isNode(objs)))).OrderBy(objs => objs.Distance).ToList();
        }

        static private bool CheckIfObjectExist(WoWGameObject aObject)
        {
            GetObjectList();

            if (myObjList.Contains(aObject))
            {
                Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Object is not gone"));
                return true;
            }

            Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Object is gathered"));
            return false;
        }
		
        static public void objs()
        {
			
            //ObjectManager.Update();
            
            //Send in the WoWGameObject to make it possible to check for isHerb and isMineral

			Flightor.Clear();

            Stopwatch timer = new Stopwatch();

            foreach (WoWGameObject objs in myObjList)
            {
                //If node is blacklisted skip it
                if (!CheckGameObjectForBlacklist(objs))
                {
                    if (objs.Z > 0 || Me.Combat) return;
                    LogApproaching(objs);
                    if (objs.Location.Distance(Me.Location) > 3)
                    {
                        timer.Start();
                        
                        myTargetObject = objs;
                        Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, 
                            string.Format("[UnderWater Collector]: Starting timer: {0} Moving to target: {1} ", 
                            timer.ElapsedMilliseconds.ToString(), myTargetObject.DisplayId.ToString()));
                        while (objs.Location.Distance(Me.Location) > 3)
                        {
                            if (Me.Combat)
                                return;
                            if (Me.IsFlying)
                                Flightor.MoveTo(objs.Location);
                            else
                            {
                                //Try to generate path to node
                                MoveResult mr = Navigator.MoveTo(objs.Location);
                                if (MoveResult.PathGenerationFailed == mr || mr == MoveResult.Failed)
                                {
                                    //if pathing fails just click to move to the node. Stop trying after 15 seconds and blacklist.
                                    WoWMovement.ClickToMove(objs.Location);

                                    while (Me.IsMoving && timer.ElapsedMilliseconds < 20000)
                                    {
                                        if (objs.Distance > 3 && timer.ElapsedMilliseconds > 20000) 
                                        {
                                            myBlacklistedObjects.Add(objs);
                                            myTargetObject = null;
                                            //Styx.CommonBot.Blacklist.Add(objs, BlacklistFlags.Node, TimeSpan.FromMinutes(15));
                                            
                                            Logging.Write(Styx.Common.LogLevel.Normal, Colors.LightSeaGreen,
                                                string.Format("[UnderWater Collector]: Failed to get to node in 20 seconds, blacklisting: {0} blacklisted nodes {1} id {2}",
                                                objs.Name, myBlacklistedObjects.Count.ToString(), objs.DisplayId.ToString()));
                                            return;
                                        }
                                    }                                    
                                }   
                            }

                            if (Math.Abs(Me.Location.X - objs.Location.X) < 1 && Math.Abs(Me.Location.Y - objs.Location.Y) < 1)
                                return;
                            //If we have tried to fly to the mine/herb in 15 seconds blacklist it
                            if (timer.ElapsedMilliseconds > 15000)
                            {
                                //Styx.CommonBot.Blacklist.Add(objs, BlacklistFlags.Node, TimeSpan.FromMinutes(15));
                                myBlacklistedObjects.Add(objs);
                                myTargetObject = null;
                                Logging.Write(Styx.Common.LogLevel.Normal, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Didn't get to node in 15 seconds, Blacklisting node {0}", objs.Name));
                                timer.Stop();
                                timer.Reset();
                                return;
                            }
                        }
                        Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Finding the node took: {0} ms", timer.ElapsedMilliseconds.ToString()));
                        timer.Stop();
                        timer.Reset();
                    }
                    else
                    {
                        Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Starting to gather node!"));
                        WoWMovement.MoveStop();
                        Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Stopped!"));
                        Thread.Sleep(200);
                        Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Dismount if not done!"));
                        Flightor.MountHelper.Dismount();
                        Thread.Sleep(1000);
                        Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: Gathering node"));
                        objs.Interact();


                        Stopwatch existTimer = new Stopwatch();
                        existTimer.Start();
                        while(CheckIfObjectExist(objs) && existTimer.ElapsedMilliseconds < 5000);
                        //Thread.Sleep(3800);
                        
                        LogGathered(objs);
                        
                        //Set finished looting
                        myLootedObject = objs;
                        myTargetObject = null;
                        
                        
                        
                        if (Me.IsSwimming)
                        {
                            Logging.Write(Styx.Common.LogLevel.Diagnostic, Colors.LightSeaGreen, string.Format("[UnderWater Collector]: I am swimming trying to asscend"));
                            WoWMovement.Move(WoWMovement.MovementDirection.JumpAscend, TimeSpan.FromMilliseconds(5000));
                        }

                        Flightor.MountHelper.MountUp();
                    }
                }
                
				return;
            }
        }
    }
}